# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: leon, xguo

import abc
from tornado import gen
import requests

from coin.base.timestamp import get_timestamp


class PrivateQueryContextBase(metaclass=abc.ABCMeta):
  def __init__(self, async_private_client, ioloop, publisher, logger, products, period):
    self._async_private_client = async_private_client
    self._ioloop = ioloop
    self._publisher = publisher
    self._logger = logger
    self._products = products
    self._period = period

    self._stopped = False
    self._querying = False

  def stop(self):
    self._async_private_client.stop()
    self._stopped = True

  def start(self):
    if self._stopped:
      return

    self._ioloop.add_callback(self._run_query)
    self._ioloop.add_timeout(self._period, self._on_timeout)

  def _on_timeout(self):
    if self._stopped:
      return

    if not self._querying:
      self._ioloop.add_callback(self._run_query)
    else:
      self._logger.warning('Still qeurying. Skip querying this time')
    self._ioloop.add_timeout(self._period, self._on_timeout)

  def _on_response(self, query, timestamp, msg):
    message = {'query': query, 'data': msg}
    self._publisher.write(timestamp, message)

  @gen.coroutine
  def _query_list_orders(self, product):
    if self._stopped:
      return

    # noinspection PyBroadException
    try:
      update = yield self._async_private_client.async_query_list_orders(product)
      timestamp = get_timestamp()
      self._on_response('query_list_orders', timestamp, update.msg)
    except requests.exceptions.Timeout as e:
      self._logger.error('query_list_orders(%s) timeout! %s' % (product.symbol, e))
    except Exception as e:
      self._logger.exception('query_list_orders(%s) exception: %s' % (product.symbol, e))

  @gen.coroutine
  def _query_balance(self):
    if self._stopped:
      return

    # noinspection PyBroadException
    try:
      update = yield self._async_private_client.async_query_account_balance()
      timestamp = get_timestamp()
      self._on_response('query_balance', timestamp, update.msg)
    except requests.exceptions.Timeout as e:
      self._logger.error('query_account_balance timeout! %s' % e)
    except Exception as e:
      self._logger.exception('query_account_balance exception: %s' % e)

  @gen.coroutine
  def _query_fills(self, product):
    if self._stopped:
      return

    # noinspection PyBroadException
    try:
      update = yield self._async_private_client.async_query_fills(product)
      timestamp = get_timestamp()
      self._on_response('query_fills', timestamp, update.msg)
    except requests.exceptions.Timeout as e:
      self._logger.error('query_fills(%s) timeout! %s' % (product.symbol, e))
    except Exception as e:
      self._logger.exception('query_fills(%s) exception: %s' % (product.symbol, e))

  @abc.abstractmethod
  @gen.coroutine
  def _run_query(self):
    raise NotImplementedError()
